// 定义默认配置项
const defaults = {
    // 设置默认的请求方式
    method: "get",
    timeout:0
}
class InterceptorManager {
    constructor() {
        this.handlers = [];
    }
    use(fulfilled,rejected){
        this.handlers.push({
            fulfilled,
            rejected
        });
        return this.handlers.length-1;
    }
    eject(index){
        if(this.handlers[index])
            this.handlers[index] = null;
    }
    clear(){
        this.handlers = [];
    }
}
class Axios {
    // 构造器函数
    constructor(instanceConfig) {
        // 增加实例属性defaults
        this.defaults = instanceConfig;
        this.interceptors = {
            request:new InterceptorManager(),
            response:new InterceptorManager(),
        }

    }
    request(configOrUrl={},config={}){
        // 判断configOrUrl是否为字符串，如果为字符串那么该参数即是请求地址
        if(typeof configOrUrl === "string"){
            config.url = configOrUrl;
        }else{
            // 如果configOrUrl不是字符串，那么可以认为configOrUrl是配置对象。
            config = configOrUrl;
        }
        config = {
            ...this.defaults,
            ...config
        }
        // 设置请求方式
        config.method = (config.method || this.defaults.method).toLowerCase();
        // 设置params
        if(config.params){
            config.url += "?"+Object.keys(config.params).map(key=>key+"="+config.params[key]).join("&");
        }
        // 拼接上baseUrl:如果地址以http://开头，且拥有baseURL属性，那么会进行拼接。
        if(!config.url.startsWith("http://") && config.baseURL){
            config.url = config.baseURL+config.url;
        }
        const dispatchRequest = function(){
            return new Promise((resolve,reject)=>{
                const request = new XMLHttpRequest();
                request.responseType = "json";
                request.timeout = config.timeout;
                request.open(config.method,config.url);
                if(config.headers){
                    for(let key in config.headers){
                        request.setRequestHeader(key,config.headers[key]);
                    }
                }
                // 请求方式为POST 且拥有请求体
                if(config.method === "post" && config.data){
                    if(typeof config.data === "string"){
                        // 1- 设置请求头Content-Type
                        request.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
                        // 2- 设置请求体
                        request.send(config.data);
                    }else{
                        // 1- 设置请求头Content-Type
                        request.setRequestHeader("Content-Type","application/json");
                        // 2- 设置请求体
                        request.send(JSON.stringify(config.data));
                    }

                }
                else{
                    request.send();
                }
                request.onload = function(){
                    if(request.status === 200){
                        resolve({
                            config,
                            data:request.response,
                            headers:request.getAllResponseHeaders(),
                            request,
                            status:request.status,
                            statusText:request.statusText
                        });
                    }else{
                        reject({
                            code:"ERR_BAD_REQUEST",
                            config,
                            message:"Request failed with status code "+request.status,
                            name:"AxiosError",
                            request,
                            response:request.response
                        })
                    }

                }
                request.onerror = function(){
                    reject({
                        code:"ERR_NETWORK",
                        config,
                        message:"Network Error",
                        name:"AxiosError",
                        request,
                        response:request.response
                    })
                }
                request.ontimeout= function(){
                    reject({
                        code:"ECONNABORTED",
                        config,
                        message:"timeout of "+config.timeout+"ms exceeded",
                        name:"AxiosError",
                        request,
                        response:request.response
                    })
                }
                request.onabort = function(){
                    reject({
                        code:"ERR_CANCELED",
                        message:"canceled",
                        name:"CanceledError"
                    })
                }
                if(config.cancelToken){
                    config.cancelToken.promise.then(value=>{
                        request.abort();
                    })
                }
            })
        }


        const chain = [dispatchRequest,undefined];

        // [{成功回调1，失败回调1},{成功回调2，失败回调2}]
        this.interceptors.request.handlers.forEach(item=>{
            if(item)
                chain.unshift(item.fulfilled,item.rejected);
        })
        // [{成功回调1，失败回调1},{成功回调2，失败回调2}]
        this.interceptors.response.handlers.forEach(item=>{
            if(item)
                chain.push(item.fulfilled,item.rejected)
        })
        //chain: [
        //  成功请求回调2，失败请求回调2
        //  成功请求回调1，失败请求回调1
        //  dispatchRequest,undefined,
        //  成功响应回调1，失败响应回调1,
        //  成功响应回调2，失败响应回调2
        // ]

        let promise = Promise.resolve(config);
        while (chain.length){
            promise = promise.then(chain.shift(),chain.shift())
        }
        return promise;
        // promise = Promise.resolve(config)
        //          .then(成功请求回调2，失败请求回调2)
        //          .then(成功请求回调1，失败请求回调1)
        //          .then(dispatchRequest,undefined)
        //          .then(成功响应回调1，失败响应回调1)
        //          .then(成功响应回调2，失败响应回调2);




        //  Promise.resolve(config).then(成功请求回调2,失败请求回调2)
        //        .then(成功请求回调1，失败请求回调1)
        //        .then(dispatchRequest,undefined)
        //        .then(成功响应回调1，失败响应回调1)
        //        .then(成功响应回调2，失败响应回调2)

        // return dispatchRequest();
    }
    get(url,config){
       return this.request(url,config);
    }
    post(url,data,config){
        return this.request(url,{
            method:"post",
            data,
            ...config
        })
    }
}

function createInstance(defaultConfig) {
    // 创建一个Axios实例赋值给常量context;
    const context = new Axios(defaultConfig);
    // instance的本质：Axios.prototype.request(将该函数的this指向到了context)
    const instance = Axios.prototype.request.bind(context);

    // 将Axios实例context的实例属性作为instance的属性。
    for(let key in context){
        instance[key] = context[key];
    }
    // 将Axios原型方法作为instance的属性
    Object.getOwnPropertyNames(Axios.prototype).forEach(key=>{
        instance[key] = Axios.prototype[key].bind(context);
    })



    return instance;
}

// 将createInstance 函数运行的结果赋值给常量axios;
// defaults是默认的配置项。
const axios = createInstance(defaults);
axios.CancelToken = class {
    constructor(executor) {
        // 当执行resolve执会将this.promise的状态更改为成功。
        this.promise = new Promise(resolve=>{
            executor(resolve)
        })
    }
}

// 默认导出axios
export default axios;